package com.medical.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medical.system.converter.MenuConverter;
import com.medical.system.enums.MenuTypeEnum;
import com.medical.system.mapper.SysMenuMapper;
import com.medical.system.model.bo.RouteBO;
import com.medical.system.model.entity.SysMenu;
import com.medical.system.model.query.MenuQuery;
import com.medical.system.model.vo.MenuOption;
import com.medical.system.model.vo.MenuVO;
import com.medical.system.model.vo.RouteVO;
import com.medical.system.service.SysMenuService;
import com.medical.system.service.SysRoleMenuService;
import com.medical.core.constant.SystemConstants;
import com.medical.core.enums.StatusEnum;
import com.medical.satoken.utils.LoginHelper;
import com.medical.system.model.form.MenuForm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    private final MenuConverter menuConverter;
    private final SysRoleMenuService roleMenuService;

    @Override
    public List<MenuVO> getMenuList(MenuQuery query, Long userId) {
        List<SysMenu> menuList = this.list(new LambdaQueryWrapper<SysMenu>()
                .like(StrUtil.isNotBlank(query.getKeywords()), SysMenu::getName, query.getKeywords())
                .orderByAsc(SysMenu::getSort));
        Set<Long> parentIds = menuList.stream()
                .map(SysMenu::getParentId)
                .collect(Collectors.toSet());
        Set<Long> menuIds = menuList.stream()
                .map(SysMenu::getId)
                .collect(Collectors.toSet());
        //过滤出那些parentIds中不再menuIds中的ID，这些就是根ID，如果父节点ID不再菜单ID中，说明该菜单为根节点（没有父级菜单）
        List<Long> rootIds = parentIds.stream().filter(id -> !menuIds.contains(id)).toList();
        return rootIds.stream()
                .flatMap(rootId -> buildMenuTree(rootId, menuList).stream())
                .collect(Collectors.toList());
//        else {
//            QueryWrapper<SysMenu> wrapper = Wrappers.query();
//            wrapper.inSql("rm.role_id", "select role_id from sys_user_role where user_id = " + userId)
//                    .like(StringUtils.isNotBlank(query.getKeywords()), "m.name", query.getKeywords());
//            menuList = baseMapper.getMenuList(wrapper);
//        }
    }

    /**
     * 递归生成菜单列表
     * @param parentId
     * @param menuList
     * @return
     */
    private List<MenuVO> buildMenuTree(Long parentId, List<SysMenu> menuList) {
        return CollectionUtil.emptyIfNull(menuList).stream()
                .filter(menu -> menu.getParentId().equals(parentId)).map(entity -> {
                    MenuVO menuVO = menuConverter.entity2Vo(entity);
                    List<MenuVO> children = buildMenuTree(entity.getId(), menuList);
                    menuVO.setChildren(children);
                    return menuVO;
                }).toList();
    }

    @Override
    public List<MenuOption> getResoutceList() {
        List<SysMenu> menuList = this.list(new LambdaQueryWrapper<SysMenu>().orderByAsc(SysMenu::getSort));
        return buildMenuOptions(SystemConstants.ROOT_NODE_ID, menuList);
    }

    @Override
    public List<MenuOption> getMenuOptions() {
        List<SysMenu> menuList = this.list(new LambdaQueryWrapper<SysMenu>().ne(SysMenu::getType, MenuTypeEnum.BUTTON.getValue()).orderByAsc(SysMenu::getSort));
        return buildMenuOptions(SystemConstants.ROOT_NODE_ID, menuList);
    }

    /**
     * 递归生成菜单下拉层级列表
     * @param parentId
     * @param menuList
     * @return
     */
    private List<MenuOption> buildMenuOptions(Long parentId, List<SysMenu> menuList) {
        List<MenuOption> menuOptions = new ArrayList<>();
        for (SysMenu sysMenu : menuList) {
            if (sysMenu.getParentId().equals(parentId)) {
                MenuOption option = new MenuOption();
                option.setValue(sysMenu.getId());
                option.setLabel(sysMenu.getName());
                option.setIcon(sysMenu.getIcon());
                option.setType(sysMenu.getType());
                List<MenuOption> subMenuOptions = buildMenuOptions(sysMenu.getId(), menuList);
                if (CollectionUtil.isNotEmpty(subMenuOptions)) {
                    option.setChildren(subMenuOptions);
                }
                menuOptions.add(option);
            }
        }
        return menuOptions;
    }

    @Override
    @Cacheable(cacheNames = "menu", key = "'routes'")
    public List<RouteVO> getRouteList(Long userId) {
        //TODO 超级管理员 返回全部菜单，否则返回当前用户菜单
        List<RouteBO> routeList;
        if (LoginHelper.isSuperAdmin()) {
            routeList = baseMapper.listRoutes(null);
        } else {
            routeList = baseMapper.listRoutes(userId);
        }
        return buildRoutes(SystemConstants.ROOT_NODE_ID, routeList);
    }

    /**
     * 递归生成菜单路由层级列表
     * @param parentId
     * @param menuList
     * @return
     */
    private List<RouteVO> buildRoutes(Long parentId, List<RouteBO> menuList) {
        List<RouteVO> routeList = new ArrayList<>();
        for (RouteBO menu : menuList) {
            if (menu.getParentId().equals(parentId)) {
                RouteVO routeVO = toRouteVO(menu);
                List<RouteVO> children = buildRoutes(menu.getId(), menuList);
                if (CollectionUtil.isNotEmpty(children)) {
                    routeVO.setChildren(children);
                }
                routeList.add(routeVO);
            }
        }
        return routeList;
    }

    /**
     * 根据RouteBO对象创建RouteVO
     * @param routeBO
     * @return
     */
    private RouteVO toRouteVO(RouteBO routeBO) {
        RouteVO routeVO = new RouteVO();
        //路由name需要驼峰， 首字母大写
//        String routeName = StringUtils.capitalize(StrUtil.toCamelCase(routeBO.getPatgetPathh(),'-'));
        routeVO.setName(routeBO.getPath());
        routeVO.setPath(routeBO.getPath());
        routeVO.setRedirect(routeBO.getRedirect());
        routeVO.setComponent(routeBO.getComponent());
        RouteVO.Meta meta = new RouteVO.Meta();
        meta.setTitle(routeBO.getName());
        meta.setIcon(routeBO.getIcon());
        meta.setRoles(routeBO.getRoles());
        meta.setHidden(StatusEnum.DISABLE.getValue().equals(routeBO.getVisible()));
        if (MenuTypeEnum.EXTLINK.equals(routeBO.getType())) {
            meta.setUrl(routeBO.getUrl());
        }
        //菜单是否开启页面缓存
        if (MenuTypeEnum.MENU.equals(routeBO.getType())
                && ObjectUtil.equals(routeBO.getKeepAlive(), 1)) {
            meta.setKeepAlive(true);
        }
        //【目录】只有一个子路由是否始终显示
        if (MenuTypeEnum.CATALOG.equals(routeBO.getType())
                && ObjectUtil.equals(routeBO.getAlwaysShow(), 1)) {
            meta.setAlwaysShow(true);
        }
        routeVO.setMeta(meta);
        return routeVO;
    }

    @Override
    public boolean saveMenu(MenuForm menuForm) {
        String path = menuForm.getPath();
        MenuTypeEnum menuType = menuForm.getType();
        //如果是目录
        if (menuType == MenuTypeEnum.CATALOG) {
            if (menuForm.getParentId() == 0 && !path.startsWith("/")) {
                menuForm.setPath("/" + path);
            }
            menuForm.setComponent("Layout");
        //如果是外链
        } else if (menuType == MenuTypeEnum.EXTLINK) {
            menuForm.setComponent(null);
        }
        SysMenu entity = menuConverter.form2Entity(menuForm);
        entity.setTreePath(generateMenuTreePath(entity.getParentId()));
        boolean result = saveOrUpdate(entity);
        if (result) {
            //刷新角色权限缓存
            roleMenuService.refreshRolePermsCache();
        }
        return result;
    }

    /**
     * 生成TreePath
     * @param parentId
     * @return 父节点路径以英文逗号(,)分割, eg: 1,2,3
     */
    private String generateMenuTreePath(Long parentId) {
        if (SystemConstants.ROOT_NODE_ID.equals(parentId)) {
            return String.valueOf(parentId);
        } else {
            SysMenu parent = getById(parentId);
            return parent != null ? parent.getTreePath() + "," + parent.getId() : null;
        }
    }

    @Override
    public MenuForm getMenuForm(Long menuId) {
        SysMenu sysMenu = getById(menuId);
        return menuConverter.entity2Form(sysMenu);
    }

    @Override
    public boolean updateMenuVisible(Long menuId, Integer visibel) {
        return update(new LambdaUpdateWrapper<SysMenu>().eq(SysMenu::getId, menuId).set(SysMenu :: getVisible, visibel));
    }

    @Override
    public boolean deleteMenu(Long id) {
        boolean result = remove(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu :: getId, id)
                .or()
                .apply("CONCAT(',', tree_path, ',') LIKE CONCAT ('%,', {0}, ',%') ", id));
        if (result) {
            roleMenuService.refreshRolePermsCache();
        }
        return result;
    }
}
